//手写Promise

//枚举Promise状态
const PROMISE_STATUS = {
    PENDING: "pending",
    FULFILLED: "fulfilled",
    REJECTED: "rejected"
}
/**
 * 把传入的参数放入微队列
 * @param {Function} function  
 */
function runMicroTask(fn) {
    //在node环境
    if (process && process.nextTick) process.nextTick(fn)
    //在浏览器环境
    else if (MutationObserver) {
        let p = document.createElement('p')
        let mo = new MutationObserver(fn)
        mo.observe(p, { childList: true })
        p.textContent = 1
    } else {
        setTimeout(fn, 0)
    }
}

/**
 * 判断是否是Promise
 * @param {Any} obj   任意值
 */
function isPromise(obj) {
    return !!(obj && typeof obj === "object" && typeof obj.then === "function")
}

class MyPromise {
    /**
     * 创建一个Promise
     * @param {Function} executor  任务执行 立即执行 
     */
    constructor(executor) {
        this._state = PROMISE_STATUS.PENDING // pending  fulfilled  rejected  状态
        this._value = undefined  // 任务执行结果  数据
        this._handlers = []; // 处理函数形成的队列
        //对错误进行监控
        try {
            executor(this._resolve.bind(this), this._reject.bind(this))
        } catch (error) {
            this._reject(error)
        }
    }

    /**
     * 向处理队列中添加任务
     * @param {Function} executor  任务执行
     * @param {string} state  任务状态
     * @param {Function} resolve  成功回调
     * @param {Function} reject  失败回调
     */
    _pushHandler(executor, state, resolve, reject) {
        this._handlers.push({ executor, state, resolve, reject })

    }

    /**
     * 状态改变时执行任务
     */
    _runhandlers() {
        if (this._state !== PROMISE_STATUS.PENDING) return
        while (this._handlers[0]) {
            const handle = this._handlers[0]
            this._runOneHandler(handler)
            this._handlers.shift()
        }
    }

    /**
     * 处理每一个handle任务
     * @param {Object} handle 
     */
    _runOneHandler({ executor, state, resolve, reject }) {
        runMicroTask(() => {
            //状态不一致 不处理
            if (this._state !== state) return
            if (typeof handle.executor !== "function") {
                this._state === PROMISE_STATUS.FULFILLED ? resolve(this._value) : reject(this._value)
                return
            }
            try {
                const result = executor(this._value)
                if (isPromise(result)) {
                    result.then(resolve, reject)
                } else {
                    resolve(result)
                }
                resolve(result)
            } catch (error) {
                reject(error)
            }
        })
    }

    /**
     * then方法
     * @param {Function} onFulfilled  成功回调
     * @param {Function} onRejected   失败回调
     */
    then(onFulfilled, onRejected) {
        return new MyPromise((resolve, reject) => {
            if (this._state !== PROMISE_STATUS.PENDING) {
                //fulfilled 
                this._pushHandler(onFulfilled, PROMISE_STATUS.FULFILLED, resolve, reject)
                //rejected
                this._pushHandler(onRejected, PROMISE_STATUS.REJECTED, resolve, reject)
                this._runhandlers()
            }
        })
    }

    /**
     * catch方法
     * @param {Function} onRejected  失败回调
     */
    catch(onRejected) {
        return this.then(null, onRejected)
    }

    /**
     * finally方法
     * @param {Function} onSettled  finally回调
     */
    finally(onSettled) {
        return this.then(data => {
            onSettled()
            return data
        }, reason => {
            onSettled()
            throw reason
        })
    }

    /**
     * 
     * @param {string} state 修改状态
     * @param {any} value 相关数据
     */
    _changeState(state, value) {
        if (this._state !== PROMISE_STATUS.PENDING) return
        this._state = state
        this._value = value
        this._runhandlers()
    }
    /**
     * 创建一个成功状态的Promise
     * @param {Any} value   任务执行结果
     */
    _resolve(data) {
        this._changeState(PROMISE_STATUS.FULFILLED, data)
    }

    /**
     * 创建一个失败状态的Promise
     * @param {Any} value   任务执行结果
     */
    _reject(reason) {
        this._changeState(PROMISE_STATUS.REJECTED, reason)
    }

    /**
     * 静态方法
     * @param {Array} promises  传入的Promise数组
     */
    static resolve(data) {
        if (data instanceof MyPromise) return data
        return new MyPromise((resolve, reject) => {
            if (isPromise(data)) {
                data.then(resolve, reject)
            } else {
                resolve(data)
            }
        })
    }

    /**
     * 静态方法
     * @param {Array} promises  传入的Promise数组
     */
    static reject(reason) {
        return new MyPromise((resolve, reject) => reject(reason))
    }

    /**
     * 静态方法
     * @param {Iterator} promises  传入的Promise数组
     */
    static all(proms) {
        return new MyPromise((resolve, reject) => {
            try {
                let i = count
                let count = 0 //promise总数
                let fulfilledCount = 0  //成功promise总数
                let result = []
                for (const pro of proms) {
                    count++
                    MyPromise.resolve(pro).then(data => {
                        fulfilledCount++
                        result[i] = data
                        if (fulfilledCount === count) {
                            resolve(result)
                        }
                    }, reject)
                }
                if (count === 0) {
                    resolve(result)
                }
            } catch (error) {
                reject(error)

            }
        })
    }

    /**
     * 静态方法
     * @param {Iterator} promises  传入的Promise数组
     */
    static allSettled(proms) {
        const ps = []
        for (const pro of proms) {
            ps.push(MyPromise.resolve(pro).then(value => ({
                status: "fulfilled",
                value
            }), reason => (
                { status: "rejected", reason }
            )))
        }
        return MyPromise.all(ps)
    }

    /**
     * 任务数组任一已决则已决，状态和其一致
     * @param {Iterator} promises  传入的Promise数组
     */
    static race(proms) {
        return new MyPromise((resolve, reject) => {
            for (const pro of proms) {
                MyPromise.resolve(pro).then(resolve, reject)
            }
        })
    }
}

